local _ENV = hf_setenv('zjhftable',true)

------------------------------------------------------------------------
--炸金花房间服务
local skynet = require "skynet"
local zjh = require "zhajinhua.clubzjh"
local utils = require "utils"
local proxypack = require "proxypack"
local msgdef = require "msgdef"
local pb = require 'protobuf'
local cjson = require "cjson"
local server_def = require "server_def"
local util = require "util"
local table_def = require "table_def"
local sharedata = require "skynet.sharedata"
local offline_op = require "offline_op"
local error_code = require "error_code"
local reason = require "reason"
local cocall = require "cocall"
local game_robot = require "zhajinhua.zjh_robot"
local constant = require "constant"
local select_server = require("router_selector")
local system_store = require "system_store"
local game_def = require "game_def"

local table_insert = table.insert
local table_remove = table.remove
local table_sort   = table.sort
local table_unpack = table.unpack
local math_floor = math.floor
local string_format = string.format
local math_random = math.random
local math_abs = math.abs
local math_min = math.min

--------------------玩家进场状态---------------------
local PLAYER_STATUS_READY = 1
local PLAYER_STATUS_NOREADY = 2
local PLAYER_STATUS_PLAYING = 3

-------------------管理---------------------
local REGISTER_CLIENT_FD = 0
local ROBOT_CLIENT_FD = -1
local OFFLINE_CLIENT_FD = -2

------------------解散管理------------------------------
local RECYCLEING_TABLE_TIMEOUT = 60

local DISS_REASON_CREATOR = 1
local DISS_REASON_UNSTART_TIME_OUT = 2
local DISS_REASON_TIME_OUT = 3
local DISS_REASON_ROUND_OVER = 4
local DISS_REASON_CLOSE_SERVER = 5

-----------------------游戏状态------------------------
local TABLE_STATUS_REGISTERED = 1 --刚刚注册
local TABLE_STATUS_WAITING_ENTER = 2
local TABLE_STATUS_WAITTING_READY = 3 --等待准备
local TABLE_STATUS_PULL_ROBOT = 4 --拉取机器人状态
local TABLE_STATUS_WAITTING_REST = 5 --游戏开始前有三秒的休息状态
local TABLE_STATUS_CHECK_START = 6 --游戏开始
local TABLE_STATUS_PLAYING = 7 --开始玩游戏
local TABLE_STATUS_GAMEOVER = 8
local TABLE_STATUS_RESTART = 9
local TABLE_STATUS_ANIMATION = 10

-----------------------超时站起------------------
local MAX_TIMEOUT_TIMES = 2
-----------------------站起原因------------------
local STANDUP_NORMAL = 0
local STANDUP_TIMEOOUT = 1
local STANDUP_CHANGETABLE = 2
local STANDUP_EXIT = 3
local STANDUP_KICK = 4

-----------------------牌局记录类型-------------------
local RECORD_TYPE_GIVEUP = 1
local RECORD_TYPE_COMPARE = 2
local RECORD_TYPE_LOOK = 3
local RECORD_TYPE_FOLLOW = 4
local RECORD_TYPE_ADD = 5
local RECORD_TYPE_RESULT = 6
local RECORD_TYPE_DIZHU = 7

local ADD_TYPE_JIA = 1
local ADD_TYPE_GEN = 2

local ROUND_TYPE_CURR = 2
local ROUND_TYPE_LAST = 1
-----------------------满轮首次比牌延迟时间-----------------
local MAX_ROUND_COMPARE_DELAY_TIME = 0.5

-------------------桌子服模式-------------------------

local handler = {}
local internal = {}

--机器人类型概率,分别对应：1:看牌型;2:焖牌型;3:土豪型
--local robot_type_rate = {40, 50, 10}

function init(params)
    global_configs = nil
    --标记房间所有玩家的clientId 包括观战者的clientId
    table_players = {}
    --管理房间内已经坐下的玩家列表
    player_info_list = {}
    --管理房间内所有玩家状态列表
    player_status_list = {}
    --坐下的玩家的顺序
    ordered_players = {}
    new_banker_uid = nil

    -----每一局的对战记录--------------
    record_list = {}

    curr_zjh_instance = nil
    --------------------游戏关服管理--------------------
    closing_server  = false
    stopping_server = false --停止服务器

    recycling_table_start_time = nil
        
    table_info = nil
    creator_uid = nil
    curr_round = nil
    ftable_expiry_time = nil
    ftable_unstart_expiry_time = nil
    ready_timeout = nil --准备状态超时

    curr_status = nil
    curr_locked_uids = {}
    reconnect_timout = {} --重连超时时间
    player_timeout   = {} --玩家超时次数

    --------------------游戏时长管理--------------------
    game_register_time = nil
    game_start_time = 0
    game_over_time  = 0
    game_rest_time  = 0
    game_animation_time = nil

    tablesvr_id = nil
    self_table_type = nil
    self_table_id = nil
    self_password = nil
    this_table_gid = nil
    self_table_pattern = nil
    self_game_type = nil
    self_club_id = nil
    total_fee = 0

    op_record_list = {} --保存上一轮和这一轮的操作记录,1:弃牌 2:比牌 3：看牌 4:跟注 5：加注 6:比牌结果
    record_pic_player = {} --记录前三局输赢玩家的uid

    self_game_config = nil

    hf_set_sentinel_end(_ENV)
end

local function send_to_gateway(uid,client_fd,...)
    if not client_fd or client_fd <= 0 then
        return
    end
    return utils.send_to_gateway(0,uid,client_fd,...)
end

local function notify_others(action,excepted_uid,msg)
    --先广播给桌子上的人
    for uid, fd in pairs(table_players) do
        if uid ~= excepted_uid then
            send_to_gateway(uid,fd,action,msg)
        end
    end
end

local function notify_all(action,msg)
    return notify_others(action,nil,msg)
end

local function is_robot(uid)
    return false
end

local function is_banker(uid)
    return new_banker_uid == uid
end

local function add_record(record_type,uid,target_uid,winner_uid,win_coins)
    local curr_round_record = op_record_list[curr_round]
    if not curr_round_record then
        curr_round_record = {}
        op_record_list[curr_round] = curr_round_record
    end

    local name,target_name,winner_name
    if uid and player_info_list[uid] then
        name = player_info_list[uid].name
    end

    if target_uid and player_info_list[target_uid] then
        target_name = player_info_list[target_uid].name
    end

    if winner_uid and player_info_list[winner_uid] then
        winner_name = player_info_list[winner_uid].name
    end

    table_insert(curr_round_record,
    {record_type = record_type,name = name,uid = uid,target_name = target_name,winner_name = winner_name,coins = win_coins})
    notify_all("zhajinhua.NTF_OP_INFO",{op_info=
    {record_type = record_type,name = name,uid = uid,target_name = target_name,winner_name = winner_name,coins = win_coins}})
end


local function check_del_record()
    for round,list in pairs(op_record_list) do
        if curr_round > round + 1 then
            op_record_list[round] = nil
        end
    end
end
--[[
    获取当前桌上的玩家数量
]]
local function get_player_num()
    local player_num = 0
    for _,uid in pairs(ordered_players) do
        player_num = player_num + 1
    end
    return player_num
end

local function get_human_num()
    local human_num = 0
    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
            human_num = human_num + 1
        end
    end
    return human_num
end

local function get_all_player_num()
    local num = 0
    for _,v in pairs(player_info_list) do
        num = num + 1
    end

    return num
end

local function get_watch_player_num()
    return get_all_player_num() - get_player_num()
end

local function get_player_state(uid)
    return player_status_list[uid]
end

local function get_least_num()
    return 2
end

local function get_player_online(uid)
    --在线状态
    if table_players[uid] and table_players[uid] == OFFLINE_CLIENT_FD then
        return false
    end
    return true
end

local function make_player_info(uid)
    local player_info = player_info_list[uid]

    local player = {
        uid = uid,
        name = player_info.name,
        position = player_info.position,
        coins = player_info.coins,
        icon = player_info.icon,
        sex = player_info.sex,
        vip_level = player_info.vip_level,
        icon_border = player_info.icon_border,
        state = get_player_state(uid),
        online = get_player_online(uid),
    }
    return player
end

local function get_extra_bill_info(uid)
    local t = {game_type=self_game_type,table_type=self_table_type}
    local player_info = player_info_list[uid]
    if not player_info then
        return t
    end

    t.client_version = player_info.client_version
    t.channel = player_info.channel
    t.cur_channel = player_info.cur_channel
    t.device_id = player_info.device_id
    t.device_brand = player_info.device_brand
    t.os_system = player_info.os_system
    t.platform = player_info.platform
    
    return t
end

local function send_next_player_operate_status()
    if not curr_zjh_instance then
        return false
    end

    local next_player_id = curr_zjh_instance:get_next_player_uid()
    local fd = table_players[next_player_id]
    if not fd then
        return false
    end

     --切换下手的时候通知下家玩家的操作按钮
    print(next_player_id,'send_next_player_operate_status')
    local player_info = player_info_list[next_player_id]
    if player_info then
        local buttons_status = curr_zjh_instance:get_buttons_status(next_player_id,player_info.coins,is_robot(next_player_id))
        send_to_gateway(next_player_id,fd,'zhajinhua.NTF_PLAYER_OPERATE_STATUS',{uid = next_player_id,buttons_status = buttons_status})
        
        return true
    end

    return false
end

local function send_self_operate_status(uid)
    if not curr_zjh_instance then
        return false
    end

    local fd = table_players[uid]
    if not fd then
        return false
    end

    local player_info = player_info_list[uid]
    if player_info then
        local buttons_status = curr_zjh_instance:get_buttons_status(uid,player_info.coins,is_robot(uid),is_robot(uid))
        send_to_gateway(uid,fd,'zhajinhua.NTF_PLAYER_OPERATE_STATUS',{uid = uid,buttons_status = buttons_status})
        return true
    end

    return false
end

local function ntf_next_turn_info()
    if curr_zjh_instance then
        local next_player_id = curr_zjh_instance:get_next_player_uid()
        local run_cycle = curr_zjh_instance:get_run_round()
        notify_all('zhajinhua.NTF_NEXT_TURN_INFO',{next_player_uid = next_player_id, next_player_operate_time = zjh.PLAY_TIME, run_cycle = run_cycle})
    end
end

local function notify_event_status(uid)
    local state = get_player_state(uid)
    local online = get_player_online(uid)
    
    local msg = {uid = uid,state = state,online = online}
    notify_others('zhajinhua.NTF_EVENT',nil,msg)
end

local function notify_player_leave(uid,status)
    notify_others('zhajinhua.NTF_PLAYER_LEAVE',uid,{
        uid = uid,
        status = status
    })
end

local function watch_session(game_session,uid,observing)
    if game_session <= 0 then
        return
    end
    local gateway_id = game_session >> 31
    local request
    if observing then
        request = 'observe_fd'
    else
        request = 'unobserve_fd'
    end

    R().gateway(gateway_id):send('.watchdog','tablesvr',request,R().get_source(),game_session,uid)
end

local function get_rank_list()
    local rsp_rank_list = {} 

    for i=1,#record_list do
        local round_result = record_list[i]
        if round_result then
            for uid, score in pairs(round_result) do
                if not rsp_rank_list[uid] then
                    local one_player_info = {}
                    one_player_info.uid = uid
                    one_player_info.score = score
                    rsp_rank_list[uid] = one_player_info
                else
                    rsp_rank_list[uid].score = rsp_rank_list[uid].score + score
                end
            end
        end
    end

    table_sort(rsp_rank_list,function(a,b) return a.score > b.score end)

    for i=1,#rsp_rank_list do
        rsp_rank_list[i].rank = i
    end

    return rsp_rank_list
end

local function get_player_score(uid,rank_list)
    local curr_score = 0
    if not rank_list then
        rank_list = get_rank_list()
    end    
    for i=1,#rank_list do
        if uid == rank_list[i].uid then
            curr_score = rank_list[i].score
        end
    end
    return curr_score
end
 
--[[
    通知所有玩家有人坐下
]]
local function notify_player_sit(uid,is_seat,is_timeout,is_kick)
    if is_seat then
        local player_info = assert(player_info_list[uid])
        local player = make_player_info(uid)
        notify_all('zhajinhua.NTF_PLAYER_SEAT',{status = is_seat,player = player})
    else
         --获取下一个出手
        local player = {uid = uid}
        local r = is_kick and nil or STANDUP_KICK
        local ntf = {
            status = is_seat,
            player = player,
            is_timeout = is_timeout,
            reason = r,
        }
        notify_all('zhajinhua.NTF_PLAYER_SEAT',ntf)
    end
end

local function get_player_ip_list()
    local player_ip_list = {}
    for uid,player_data in pairs(player_info_list) do
        if player_data.login_ip then
            table_insert(player_ip_list,player_data.login_ip)
        end
    end
    return player_ip_list
end

local function leave_round(uid)
    if curr_zjh_instance and not curr_zjh_instance:is_game_over() then
        local is_trun_next = curr_zjh_instance:leave(uid)
        if is_trun_next then
            curr_zjh_instance:turn_next_player()
            ntf_next_turn_info()
            send_next_player_operate_status()
        end
    end
end

--[[
    设置玩家坐下
]]
local function sit_down(uid,pos)
    ordered_players[pos] = uid
    local player_info = assert(player_info_list[uid],'sit_down no player info' .. tostring(uid))
    player_info.position = pos
    player_status_list[uid] = PLAYER_STATUS_READY
    player_timeout[uid] = nil

    notify_player_sit(uid,true)
end

--[[
    设置玩家站起z
]]
local function stand_up(uid,is_timeout,is_kick)
    local player_info = player_info_list[uid] or {}
    if not player_info.position then
        leave_round(uid)
        return false
    end
    
    notify_player_sit(uid,false,is_timeout,is_kick)

    local pos = player_info.position

    leave_round(uid)

    player_info.position = nil
    ordered_players[pos] = nil
    --玩家站起清除掉玩家的状态
    player_status_list[uid] = nil
end

local function unlock_one_player(uid,table_gid)
    R().exdbsvr(1):send('.tlock_mgr','unset_on_table',uid,this_table_gid)
    curr_locked_uids[uid] = nil
    R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type=0})
end

local function on_leave(uid)
    local player_info = player_info_list[uid]
    if player_info then
        local is_robot = is_robot(uid)
        local game_seesion = table_players[uid]
        stand_up(uid)

        local init_coins = player_info.init_coins or 0
        player_status_list[uid] = nil
        player_info_list[uid] =nil
        reconnect_timout[uid] = nil
        table_players[uid] = nil

        if not is_robot then
            unlock_one_player(uid,this_table_gid)
            watch_session(game_seesion,uid,false)
            skynet.send(".table_mgr", "lua", "leave", uid)
        end

        --清掉牌局中的当前轮数的分数
        if curr_zjh_instance then
            curr_zjh_instance:clear_curr_round_score(uid)
        end
    end

end

local function leave(uid,reason)
    assert(table_players[uid])

    --如果是网络断开了
    if reason then
        local player_info = player_info_list[uid]
         if player_info then
            --如果不是观战 那么将角色标记为离线状态
            assert(table_players[uid] ~= OFFLINE_CLIENT_FD)
            table_players[uid] = OFFLINE_CLIENT_FD
            if player_info.position then
                notify_event_status(uid, reason)
            end
            print("leave by offline")
            reconnect_timout[uid] = util.get_now_time()
            return
        end
    end

    on_leave(uid)
end

local function check_auto_bet(curr_time)
    --不是机器人才有自动跟注
    local next_player_id = curr_zjh_instance:get_next_player_uid()
    local operate_delay_time = curr_zjh_instance:get_operate_delay_time()
    if not is_robot(next_player_id) then
        local player_info = player_info_list[next_player_id]
        if player_info then
            if curr_zjh_instance:is_auto_bet(next_player_id) then
                local buttons_status = curr_zjh_instance:get_buttons_status(next_player_id,player_info.coins,is_robot(next_player_id))
                --判断是否需要延时下注
                if buttons_status.can_continue_bet then
                    if operate_delay_time then
                        if curr_time >= operate_delay_time then
                            ntf_next_turn_info()
                            send_next_player_operate_status()
                            skynet.send(skynet.self(),'lua','REQ_ADD_SCORE',next_player_id,{add_type = 2},table_players[next_player_id])
                            --curr_zjh_instance:set_auto_bet(next_player_id,false)
                            curr_zjh_instance:clear_operate_delay_time()
                        end
                    else
                        if curr_time - (curr_zjh_instance:get_play_end_time() - zjh.PLAY_TIME) >= 1 then
                            skynet.send(skynet.self(),'lua','REQ_ADD_SCORE',next_player_id,{add_type = 2},table_players[next_player_id])
                        end
                    end
                else
                    --不能跟注清除状态
                    if operate_delay_time then
                        if curr_time >= operate_delay_time then
                            ntf_next_turn_info()
                            send_next_player_operate_status()
                            curr_zjh_instance:set_auto_bet(next_player_id,false)
                            curr_zjh_instance:clear_operate_delay_time()
                        end
                    else
                        curr_zjh_instance:set_auto_bet(next_player_id,false)
                    end
                end
            else
                --如果不是自动下注 那么检查是否需要延长操作时间
                if operate_delay_time then
                    if curr_time >= operate_delay_time then
                        ntf_next_turn_info()
                        send_next_player_operate_status()
                        curr_zjh_instance:clear_operate_delay_time()
                    end
                end
            end
        end
    end
end

local function continue_compare(curr_time)
    --检查有没有需要继续比牌的玩家
    local next_player_id = curr_zjh_instance:get_next_player_uid()
    local player_info = player_info_list[next_player_id]
    if player_info then
        local buttons_status = curr_zjh_instance:get_buttons_status(next_player_id,player_info.coins,is_robot(next_player_id))
        local run_round = curr_zjh_instance:get_run_round()
        --需要强制比牌并且有操作延时那么才进行比牌
        if buttons_status.force_compare_uid then
            local roomdata = self_game_config
            if roomdata and run_round >= roomdata.comparable_bet_round then --满轮首次比牌延迟0.5s
                curr_zjh_instance:set_max_round_frist_compare_delay_time(MAX_ROUND_COMPARE_DELAY_TIME)
            end

            local operate_delay_time = curr_zjh_instance:get_operate_delay_time()
            if operate_delay_time then
                if curr_time >= operate_delay_time then
                    skynet.send(skynet.self(),'lua','REQ_COMPARE_CARD',next_player_id,{dst_uid=buttons_status.force_compare_uid},table_players[next_player_id],true)
                    curr_zjh_instance:set_operate_delay_time()
                end
            else
                skynet.send(skynet.self(),'lua','REQ_COMPARE_CARD',next_player_id,{dst_uid=buttons_status.force_compare_uid},table_players[next_player_id],true)
                curr_zjh_instance:set_operate_delay_time()
            end
            return true
        end
    end

    return false
end

local function check_trusteed_player(curr_time)
    if curr_time >= curr_zjh_instance:get_play_end_time() then
        --第一次超时棋牌 第二次超时才站起
        local uid = curr_zjh_instance:get_next_player_uid()
        player_timeout[uid] = (player_timeout[uid] or 0) + 1
        print("player_timeout[uid]===========",uid,player_timeout[uid])
        if player_timeout[uid] >= MAX_TIMEOUT_TIMES then
            stand_up(uid,true)
        else
            skynet.send(skynet.self(),'lua','REQ_GIVE_UP',uid,{},table_players[uid],true) --系统主动弃牌
        end
        --如果该角色还是处于REGISTER_CLIENT_FD状态那么将玩家加入超时队列
        if table_players[uid] == REGISTER_CLIENT_FD then
            reconnect_timout[uid] = util:get_now_time()
        end
    else
        --需要继续比牌优先继续比牌 没有继续比牌再检查是否需要自动下注
        if not continue_compare(curr_time) then
            check_auto_bet(curr_time)
        end
    end
end

local function check_play(curr_time)
    if curr_zjh_instance:is_game_over() then
        return true
    end

    --轮到我出手了然而没有出手那么进行托管 托管逻辑就只是帮玩家站起
    check_trusteed_player(curr_time)

    return false
end

---------------------------------------------------------------------------
local function lock_one_player(uid,table_gid)
    local ok,succ = R().exdbsvr(1):call('.tlock_mgr','set_on_table',uid,table_gid,table_gid)
    if not ok then
        errlog(uid,'failed to set_on_table')
        return
    end

    if not succ then
        return
    end

    curr_locked_uids[uid] = true

    R().friendsvr(1):send('.info_mgr','update_info',uid,{curr_game_type = self_game_type, curr_table_type = self_table_type})

    return 0
end

local function get_all_human_uids()
    local uids = {}
    for uid,fd in pairs(table_players) do
        table_insert(uids,uid)
    end
    return uids
end

local function unlock_all_players()
    local uids = get_all_human_uids()
    for _,uid in pairs(uids) do
        unlock_one_player(uid,this_table_gid)
    end
end
---------------------------------------------------------------------------
local function get_player_enter_data(uid)
     --先拉取玩家信息
    local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
    if not ok then
        errlog(uid,'failed to get base_data',uid)
        return
    end
   
    --再拉取玩家的登入信息 跟大厅拉取
    local ok,enter_data = R().hallsvr({key=uid}):call('.msg_handler','get_enter_data',uid)
    if not ok then
        errlog(uid,'failed to get enter_data')
        enter_data = {}
    end
    
    local player_data = {
        uid = base_data.uid,
        name = enter_data.name or '',
        coins = base_data.coins,
        icon = enter_data.icon or '',
        sex = enter_data.sex or 1,
        affect_count = base_data.affect_count,
        affect_rate = base_data.affect_rate,
        vip_level = base_data.vip_level,
        icon_border = enter_data.icon_border,
        safe_box = base_data.safe_box,
    }

    return player_data    
end

local function get_table_conf()
    local conf = {}
    conf.curr_round = curr_round
    conf.creator_uid = creator_uid
    conf.password = self_password

    local roomdata = self_game_config
    if roomdata then
        conf.dizhu = roomdata.dizhu
        conf.dingzhu = roomdata.dingzhu
        conf.max_bet_round = roomdata.max_bet_round
        conf.comparable_bet_round = roomdata.comparable_bet_round
        conf.max_look_round = roomdata.max_look_round
        conf.cost = roomdata.cost
        conf.table_name = roomdata.name
        conf.max_coins  = roomdata.max
        conf.table_type = self_table_type
    end

    local curr_time = util.get_now_time()
    if game_rest_time > curr_time then
        conf.end_time = game_rest_time - curr_time
    end

    return conf
end

local function get_player_info_list()
    local tmp_player_info_list = {}

    for _, uid in pairs(ordered_players) do
        local data = player_info_list[uid]
        if data then
            local player = make_player_info(uid)
            table_insert(tmp_player_info_list,player)
        end
    end
    return tmp_player_info_list
end

local function notify_player_enter(uid)
    local player_info = assert(player_info_list[uid])
    local player = make_player_info(uid)

    local play_effect = false
    local vip_level_conf = utils.getDataBykv(global_configs.vip,"level",player_info.vip_level or 0)
    if vip_level_conf and vip_level_conf.privilege[game_def.VIP_PRIVILEGE_TYPE_SIX] then
        play_effect = true
    end
    if curr_zjh_instance and curr_zjh_instance:check_player_in_round(uid) then
        play_effect = false
    end
    local enter_word = vip_level_conf.enter_word
    notify_all('zhajinhua.NTF_PLAYER_ENTER',{play_effect = play_effect,player = player,enter_word = enter_word})
end

local function set_ready(uid,ready)
    assert(player_status_list[uid])
    if ready then
        player_status_list[uid] = PLAYER_STATUS_READY
    else
        player_status_list[uid] = PLAYER_STATUS_NOREADY 
    end
    notify_event_status(uid)

    return true
end


local function enter(uid,client_fd,msg)
    dbglog("uid", uid, "enter")

    local roomdata = self_game_config
    if not roomdata then
        errlog("unkown table type!!!!",table_type)
        return false,-1
    end

    local ok,curr_coins = R().basesvr({key=uid}):call('.msg_handler','get_coins',uid)
    if not ok or not curr_coins then
        errlog(uid,'failed to get base_data',uid)
        return false,-2
    end

    if curr_coins < roomdata.min then
        return false,error_code.GOLD_IS_NOT_ENOUGH
    end

    if roomdata.max ~= 0 and curr_coins > roomdata.max then
        return false,error_code.GOLD_OUT_OF_MAX
    end

    --获取玩家进入游戏数据
    local data = get_player_enter_data(uid)
    if not data then
        errlog(uid,'failed to get_player_enter_data')
        return false,error_code.CANNOT_ENTER_TEMOPORARILY
    end

    if table_players[uid] then
        local player_info = player_info_list[uid]
        if player_info and player_info.position then
            dbglog(uid, 'duplicate enter again')
            player_info.name = data.name
            player_info.icon = data.icon
            player_info.coins = data.coins
            player_info.sex = data.sex
            player_info.roomcards = data.roomcards
        end
    else
        --已经进入过其他房间了
        if not lock_one_player(uid,this_table_gid) then
            errlog(uid,'curr_round == 0 failed to lock player,you may have been in other table')
            return false,error_code.CANNOT_ENTER_FTABLE_LOCKED
        end
        dbglog('table_info.is_authorized_seat', table_info.is_authorized_seat)

        --直接安排位置坐下
        local position = 1
        while ordered_players[position] do
            position = position + 1
        end

        if position > zjh.MAX_PLAYER_NUM then --如果已经超过最大人数了,加入观战列表
            local watch_num = get_watch_player_num()
            if watch_num >= zjh.MAX_WATCH_PLAYER_NUM then
                dbglog(uid,'that watch player num is enough')
                unlock_one_player(uid,this_table_gid)
                return false,error_code.FULL_WATCH_PLAYERS_IN_FRIEND_ROOM
            end
            dbglog(uid, 'watch_player_list')
            player_info_list[uid] = data
        else
            dbglog(uid, 'add to player_info_list')
            player_info_list[uid] = data
            sit_down(uid,position)
            set_ready(uid, true)
        end
    end

    table_players[uid] = client_fd
    reconnect_timout[uid] = nil

    local player_info = player_info_list[uid]
    if player_info then
        player_info.channel = msg.channel
        player_info.cur_channel = msg.cur_channel
        player_info.device_id = msg.device_id
        player_info.device_brand = msg.device_brand
    end

    local enter_info = {}
    enter_info.ftable_info = get_table_conf()
    enter_info.player_info_list = get_player_info_list()
    if curr_zjh_instance then
        enter_info.game_status = curr_zjh_instance:get_game_status(uid,player_info.coins,is_robot(uid))
    end

    print_r(enter_info)    
    return true,{game_type = self_game_type,table_type = self_table_type, zhajinhua_enter_info = enter_info}
end

local function are_all_players_ready()
    --这里的玩家数量一定是已经坐下的玩家数量了
    local player_num = get_player_num()
    if player_num < zjh.MIN_PLAYER_NUM then
        return false
    end
    
    local count = 0
    --检查座位上的玩家状态
    print(tostring_r(player_status_list))
    for _, uid in pairs(ordered_players) do
        local status = player_status_list[uid]
        if status == PLAYER_STATUS_READY then
            count = count + 1
        end
    end

    if count < zjh.MIN_PLAYER_NUM then
        return false
    end
    return true
end

local function is_ready_timeout(curr_time)
    if curr_time - ready_timeout  >= 5 then
        return true
    end
    return false
end

local function can_start()
    if curr_zjh_instance then
        return false,-1
    end

    local sitdown_num = get_player_num()
    if sitdown_num < zjh.MIN_PLAYER_NUM then
        return false,-2
    end

    --call回来再次检查玩家数量
    if get_player_num() < zjh.MIN_PLAYER_NUM then
        return false,-2
    end

    local zjh_instance = zjh:new()
    print("qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",zjh_instance)
    local is_control_systerm_win = false
    zjh_instance:init(is_control_systerm_win,self_game_config)
    zjh_instance:bind_type(self_table_type)

    --按位置索引顺序进入游戏
    for i=1, zjh.MAX_PLAYER_NUM, 1 do
        local uid = ordered_players[i]
        if uid then
            local player_info = player_info_list[uid]
            if player_info then
                zjh_instance:enter(uid,player_info.name)
            end
        end
    end

    local ok = zjh_instance:check()
    if not ok then
        return false,-3
    end

    zjh_instance:shuffle()

    local special_uid,second_uid,deal_card_type 
    zjh_instance:deal(special_uid,second_uid,deal_card_type)
    
    --设置庄家状态
    zjh_instance:setingbanker_status(new_banker_uid)

    --设置所有玩家都处于游戏状态
    for _uid,status in pairs(player_status_list) do
        player_status_list[_uid] = PLAYER_STATUS_PLAYING
    end
    return zjh_instance
end

local function reduce_coins(uid,cost_coins,reason,...)
    print("================cost_coins================",cost_coins)
    local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler','reduce_coins',uid,cost_coins,reason,...)
    if not ok then
        errlog(uid, "CZJH reduce_coins error because ok is nil")
        return
    end

    if not succ then
        errlog(uid, "CZJH reduce_coins error because succ is nil")
        return
    end

    R().basesvr{key=uid}:send('.msg_handler','add_lose_coins',uid,cost_coins)

    return {
        curr_coins = ret.curr
    }
end

--扣除底注
local function bet_begin_score()
    local roomdata = self_game_config
    if not roomdata then
        errlog(self_table_type, "CZJH bet_begin_score not find roomdata")
        return false
    end

    local player_list = curr_zjh_instance:get_player_list()
    local reduce_coins_list = {}
    for _, uid in pairs(player_list) do
        local robot = is_robot(uid)
        table_insert(reduce_coins_list,{f = reduce_coins,id = uid,
            params = {uid,roomdata.dizhu,reason.BET_COIN,{is_robot=robot}, get_extra_bill_info(uid)}})
    end

    --扣钱    
    local ok,results = cocall(5,reduce_coins_list)
    if not ok then
        errlog('ZJH:bet_begin_score failed to cocall',tostring_r(results))
        return false
    end

    print(tostring_r(results))
    for uid,ret in pairs(results) do
        if ret and player_info_list[uid] then
            player_info_list[uid].coins = ret.curr_coins
        end
    end

    return true
end

local function notify_start(cur_instance)
    print(cur_instance:get_next_player_uid(),'now notify game is started....')

    if bet_begin_score() then
        curr_zjh_instance:bet_begin_score()
    end

    local ntf = {}
    for uid, player_info in pairs(player_info_list) do
        if not is_robot(uid) then
            ntf.game_status = cur_instance:get_game_status(uid,player_info.coins,is_robot(uid))
            ntf.fround = curr_round
            ntf.player_info = get_player_info_list()
            send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_START',ntf)
        end
        --添加记录
        local bet_score = cur_instance:get_player_bet_score(uid)
        if bet_score > 0 then
            add_record(RECORD_TYPE_DIZHU,uid,nil,nil,bet_score)
        end
    end

    --通知庄家的按钮状态
    send_next_player_operate_status()
end

local function check_start(curr_time)
    local zjh_instance,msg = can_start()
    if not zjh_instance then
        dbglog('failed to can_start()',msg)
        return
    end

    print('now start the game...')
    curr_zjh_instance = zjh_instance
    return true
end

local function get_result_info(game_result)
    local rand_info = {}
    local winners = game_result.winners
    local losers = game_result.losers
    for _, round_info in ipairs(winners) do
        rand_info[round_info.uid] = round_info.add_score
    end
    for _, round_info in ipairs(losers) do
        rand_info[round_info.uid] = round_info.add_score
    end
    return rand_info
end

local function add_coins(uid,coins,reason,...)
    local ok,succ,ret = R().basesvr{key=uid}:call('.msg_handler','add_coins',uid,coins,reason,...)
    if not ok then
        errlog(uid,'failed to add_coins ok is nil',coins)
        return
    end
    if not succ then
        errlog(uid,'failed to add_coins succ is nil',coins)
        return
    end

    R().basesvr{key=uid}:send('.msg_handler','sub_lose_coins',uid,coins)
    
    return {
        curr_coins = ret.curr,
    }
end

local function notify_compare_player_card()
    --通知玩家跟其比过牌的信息
    for _,uid in pairs(ordered_players) do
        local player_status = player_status_list[uid]
        if player_status and player_status == PLAYER_STATUS_PLAYING then
            --自己没弃牌才能看到其他人的牌型
            if not curr_zjh_instance:is_give_up(uid) then
                local player_card_list = curr_zjh_instance:get_compare_card_list(uid)
                send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_COMPARE_PLAYER_CARD',{player_card_list = player_card_list})
            end
        end
    end
end

local function give_won_coins(uid,coins,reason)
    local robot = is_robot(uid)
    local ok,succ,ret = R().basesvr({key=uid}):call('.msg_handler',
        'give_won_coins',uid,coins,self_game_type,reason,{is_robot=robot},get_extra_bill_info(uid))
    if not ok then
        errlog(uid,'failed to give_won_coins',coins,succ)
        return
    end
    if not succ then
        errlog(uid,'failed to give_won_coins',coins)
        return
    end

    return {curr_coins = ret.curr,won_coins = ret.chged}
end

local function add_players_other_card_record_atts(winners,losers,player_realwin_map,fee_map)
    for _, player in pairs(winners) do        
        player.pay_fee   = fee_map[player.uid] or 0
        player.is_robot  = is_robot(player.uid)
        player.add_score = player_realwin_map[player.uid]
        player.is_banker = is_banker(player.uid)
    end

    for _, player in pairs(losers) do        
        player.pay_fee   = fee_map[player.uid] or 0
        player.is_robot  = is_robot(player.uid)
        player.is_banker = is_banker(player.uid)
    end
end

local function get_player_curr_coins(uid)
    if player_info_list[uid] then
        return player_info_list[uid].coins
    else
        --print("get_player_curr_coins---->",uid)
        local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
        if not ok then
            errlog(uid,'get_player_curr_coins-->failed to get base_data')
            return 0
        end

        return base_data.coins
    end

    return 0
end

local function write_card_record_log(winners, losers,player_realwin_map,fee_map)
    add_players_other_card_record_atts(winners,losers,player_realwin_map,fee_map)

    local player_win = 0
    local human_fee  = 0
    local total_num = 0
    local add_score_map = {}
    local player_coins_map = {}
    for _,player in pairs(winners) do
        if not player.is_robot then
            player_win = player_win + player.add_score
            human_fee = human_fee + (fee_map[player.uid] or 0)

            player_coins_map[player.uid] = player.add_score + (fee_map[player.uid] or 0)
        end
        add_score_map[player.uid] = player.add_score
        total_num = total_num + 1
    end

    for _,player in pairs(losers) do
        if not player.is_robot then
            player_win = player_win + player.add_score
            player_coins_map[player.uid] = player.add_score 
        end
        add_score_map[player.uid] = player.add_score
        total_num = total_num + 1
    end

    local change_store_coins = -(player_win + human_fee)

    local str_date = os.date("%Y%m%d%H%M%S")
    local side_list = {}
    local all_cards = curr_zjh_instance:get_all_player_tile_list()
    local player_list = curr_zjh_instance:get_player_list()
    for side,uid in pairs(player_list) do
        local side_info = {}
        side_info.uid = uid
        side_info.side = side
        side_info.cards = all_cards[uid] or {}
        side_info.card_type = curr_zjh_instance:get_card_type(uid)
        side_info.bet_coins = curr_zjh_instance:get_player_bet_score(uid)
        side_info.add_score = add_score_map[uid] or 0
        side_info.win = (add_score_map[uid] or 0) > 0

        table_insert(side_list,side_info)
    end

    local roomdata = self_game_config or {}
    local total_score  = curr_zjh_instance:get_table_total_score()
    local run_round = curr_zjh_instance:get_run_round()
    local end_type = run_round < (roomdata.comparable_bet_round or 0) and 1 or 2
    local exinfo = {
        dizhu = roomdata.dizhu or 0,
        round = run_round,
        total_score = total_score,
        end_type = end_type,
        system_result = 0,
        control_uid = 0,
    }
    billlog({
        op = "card_record",
        table_gid = str_date .. "_" .. self_table_id, 
        game_type = self_game_type,table_type = self_table_type, 
        begin_time = game_start_time,end_time = util.get_now_time(),
        curr_round = curr_round, password = self_password,
        winner_list = winners, loser_list = losers,system_win = -player_win, 
        address = skynet.address(skynet.self()),
        side_list = side_list,
        exinfo = exinfo,
        total_num = total_num,
    })

    local total_coins = 0
    for uid,add_score in pairs(player_realwin_map) do
        if not is_robot(uid) then
            total_coins = total_coins + math_abs(add_score) + math_abs(fee_map[uid] or 0)
            --R().basesvr({key=uid}):send('.msg_handler','add_today_win_coins',uid,add_score)
            R().basesvr({key=uid}):send('.msg_handler','add_play_count',uid,1)
        end
    end

    for _,record in pairs(losers) do
        -- local curr_coins = get_player_curr_coins(record.uid)

        if not is_robot(record.uid) then
            total_coins = total_coins + math_abs(record.add_score) + math_abs(fee_map[record.uid] or 0)
            R().basesvr({key=record.uid}):send('.msg_handler','add_play_count',record.uid,1)
        end

        -- if not is_robot(record.uid) and curr_coins <= constant.POCHAN_COINS then --记录破产日志
        --     billlog({op = "bankrupt_register",uid = record.uid,game_type = self_game_type,
        --         table_type = self_table_type,
        --         ret = curr_coins,
        --     })
        -- end
    end

    if self_club_id then
        R().clubsvr(1):send('.club_mgr','add_club_player_coins',self_club_id,player_coins_map)
    end

    return total_coins
end

local function send_real_horse_message(winners_list)
    for _, player_record in pairs(winners_list) do
        local uid = player_record.uid
        if player_record.add_score > 0 then
            local player_info = player_info_list[uid]
            if player_info then
                R().mailsvr(1):send('.opration_message_worker','send_real_horse_message',constant.BROADCAST_IDS.BIDS_ZJH,
                {name = player_info.name,coin = player_record.add_score,vip_level = player_info.vip_level})
            end
        end
    end
end

--记录前三局输赢玩家的uid
local function robot_use_pic(winners,losers)
    local win_list = record_pic_player.win_list
    local lose_list = record_pic_player.lose_list
    if not win_list then
        win_list = {}
        record_pic_player.win_list = win_list
    end
    if not lose_list then
        lose_list = {}
        record_pic_player.lose_list = lose_list
    end
    if #win_list >= 3 then
        table_remove(win_list,1)
    end
    if #lose_list >= 3 then
        table_remove(lose_list,1)
    end
    win_list[#win_list+1] = {}
    lose_list[#lose_list+1] = {}

    local uid_win_list = win_list[#win_list]
    local uid_lose_list = lose_list[#lose_list]
    
    for _, player in pairs(winners) do
        if player.uid then
            uid_win_list[player.uid] = true
        end
    end
    for _, player in pairs(losers) do
        if player.uid then
            uid_lose_list[player.uid] = true
        end
    end
end

local function audit_game_result(game_result)
    ---------------------------结算界面-------------------------------------
    --通知玩家跟其比过牌的信息
    notify_compare_player_card()

    assert(not record_list[curr_round])
    local rand_info = get_result_info(game_result)
    local winners = game_result.winners
    local losers = game_result.losers
    record_list[curr_round] = rand_info
    local winplayers = {}
    local loseplayers = {}
    local roomdata = self_game_config
    local fee_percent = (roomdata.cost or 5 )/ 100

    local total_score = curr_zjh_instance:get_table_total_score()
    --获取当前金币

    local win_score = 0
    print("uuuuuuuuuuuuuuuuuuuuuuuuuuu")
    for _, player_record in pairs(winners) do
        new_banker_uid = player_record.uid
        win_score = player_record.add_score
        table_insert(winplayers,{ f = give_won_coins,id = player_record.uid,params = {player_record.uid,total_score,reason.WIN_COIN} })
        
        print("ssssssssssssssssssssssssss")
        
    end

    for _, player_record in pairs(losers) do
        R().basesvr({key=player_record.uid}):send('.msg_handler','add_losing_times',player_record.uid,self_game_type)
    end

    --加钱    
    local ok,winresults = cocall(5,winplayers)
    if not ok then
        errlog('failed to cocall',tostring_r(results))
        return
    end

    --扣台费
    local cost_player = {}
    local fee_map = {}
    local player_realwin_map = {}
    for _, player_record in pairs(winners) do
        local uid = player_record.uid
        local fee_score = math_floor(player_record.add_score * fee_percent) 
        player_realwin_map[uid] = player_record.add_score - fee_score
        player_record.add_score = total_score - fee_score
        fee_map[uid] = fee_score
        total_fee = total_fee + fee_score

        table_insert(cost_player,{ f = reduce_coins,id = uid,
            params = {uid,fee_score,reason.PAY_FEE,{is_robot = is_robot(uid)}, get_extra_bill_info(uid)} })
    end

    local ok,results = cocall(5,cost_player)
    if not ok then
        errlog('pay_fee failed to cocall',tostring_r(results))
        return false
    end

    for uid,ret in pairs(results) do
        if ret then
            local player_info = player_info_list[uid]
            if player_info then
                --player_info.coins = ret.curr
                player_info.coins = ret.curr_coins
            end
        end
    end

    for _, player_record in ipairs(winners) do
        local isrobot = is_robot(player_record.uid)
        player_record.left_score = get_player_curr_coins(player_record.uid)
        local player_info = player_info_list[player_record.uid]
        if player_info then
            if isrobot then
                player_info.valid_times =  player_info.valid_times + 1
            end
        end
        --添加牌局记录
        add_record(RECORD_TYPE_RESULT,player_record.uid,nil,nil,player_record.add_score)
    end
    for _, player_record in ipairs(losers) do
        local isrobot = is_robot(player_record.uid)
        player_record.left_score = get_player_curr_coins(player_record.uid)
        local player_info = player_info_list[player_record.uid]
        if player_info then
            if isrobot then
                player_info.valid_times =  player_info.valid_times + 1
            end
        end
    end


    notify_all('zhajinhua.NTF_GAMEOVER', {winners = winners,losers = losers})
    send_real_horse_message(winners)
    robot_use_pic(winners,losers)

    local total_coins = write_card_record_log(winners,losers,player_realwin_map,fee_map)
    
    return true
end

local function check_reconnect_timeout(curr_time)
    --检查离线超时玩家是否需要做踢掉操作
    for uid, offline_time in pairs(reconnect_timout) do
        if curr_time - offline_time >= 120 then
            leave(uid)
        end
    end
end

local function have_player()
    for uid,_ in pairs(player_info_list) do
        if not is_robot(uid) then
            return true
        end
    end
    return false
end

local function dissmiss_table()
    local uids = {}
    for uid,player_info in pairs(player_info_list) do
        local game_session = table_players[uid]
        local robot = is_robot(uid)
        leave(uid)
        if not robot then
            send_to_gateway(uid,game_session,'zhajinhua.RSP_LEAVE',{result=error_code.RSP_SUCESS})
            watch_session(game_session,uid,false)
        end
        skynet.send('.table_mgr','lua','leave',uid)

        table_insert(uids,uid)
    end

    --告知fmatchsvr该桌子已被解散
    if self_club_id then
        if total_fee > 0 then
            R().clubsvr(1):call('.club_mgr','add_club_income',self_club_id,{password = self_password,total_fee = total_fee})
        end
        R().fmatchsvr(1):send('.table_mgr','dismiss_club_friend_table',self_password,this_table_gid)
    end


    skynet.send('.table_mgr','lua','on_table_delete',self_table_id,uids)    --删除状态

    return true
end

local function check_stop_table()
    if stopping_server then        
        billlog({op = "stop_table",status = curr_status,password = self_password})
        closing_server = true --直接关闭桌子
        return true
    end

    return false
end

local function check_close_table(curr_time)
    if not game_register_time then
        game_register_time = curr_time
    end

    local closable = false
    if closing_server then
        closable = true
    else 
        --如果已经没有玩家了 并且桌子已经处于游戏结束状态那么就关闭游戏 游戏没有开局 那么就关闭游戏了
        if not have_player() and not curr_zjh_instance and curr_round ~= 0 then
            closable = true
        end

        if not have_player() and curr_round == 0 and curr_time - game_register_time >= 30 then
            closable = true
        end
    end

    if not closable then
        return
    end

    local ok,ret = xpcall(dissmiss_table,debug.traceback)
    if not ok then
        errlog(ret)
    end

    billlog({op = "close_table",status = curr_status,password = self_password})
    dbglog('now delete this table',self_table_id,uids)

    skynet.exit()
end

local function reset_all_player_ready()
    for _, uid in pairs(ordered_players) do
        player_status_list[uid] = PLAYER_STATUS_READY
    end
end

local function finish_game()
    local ok,result = curr_zjh_instance:get_game_result()
    if not ok then
        return
    end
    
    return result
end

local function kick_player_standup()
    local roomdata = self_game_config
    if not roomdata then
        errlog('pay_fee fail because roomdata is nil')
        return
    end

    --这里在检查一把是否要将玩家和机器人进行站起或者离开
    local robot_ids_list = {}
    for _,uid in pairs(ordered_players) do
        local player_info = player_info_list[uid]
        if player_info then
            if player_info.coins < roomdata.min or player_info.coins < roomdata.cost then
                print("is_kick====11111",player_info.coins,roomdata.min,roomdata.cost)
                stand_up(uid,false,true)
            elseif roomdata.max ~= 0 and player_info.coins > roomdata.max then
                print("is_kick====2222",player_info.coins,roomdata.max)
                stand_up(uid,false,true)
            end
        end
    end
end

local function notify_count_down()
    notify_all('zhajinhua.NTF_COUNTDOWN',{end_time = zjh.GAME_REST_TIME})
end

local function notify_cancel_count_down()
    notify_all('zhajinhua.NTF_CANCEL_COUNTDOWN',{})
end

local function players_num_meet_conditions()
    --这里的玩家数量一定是已经坐下的玩家数量了
    local player_num = get_player_num()
    if player_num < get_least_num() then
        return false
    end

    --检查座位上的玩家状态
    local count = 0
    for _, uid in pairs(ordered_players) do
        local status = player_status_list[uid]
        if status == PLAYER_STATUS_READY then
            count = count + 1
        end
    end

    if count < get_least_num() then
        return false
    end

    return true
end

-------------------------------游戏主循环------------------------
function update(curr_time)
    --print('=============curr status',tostring(curr_status),self_table_id)
    if curr_status == TABLE_STATUS_WAITTING_READY then
        if players_num_meet_conditions() then
            curr_status = TABLE_STATUS_WAITTING_REST
            game_rest_time = curr_time+zjh.GAME_REST_TIME
            notify_count_down()
        end
    elseif curr_status == TABLE_STATUS_WAITTING_REST then
        if curr_time > game_rest_time then
            curr_status = TABLE_STATUS_CHECK_START
        elseif not players_num_meet_conditions() then
            curr_status = TABLE_STATUS_WAITTING_READY
        end
    elseif curr_status == TABLE_STATUS_CHECK_START then
        if check_start(curr_time) then 
            --第一次开始，在匹配房标记一下
            curr_round = curr_round + 1
            if curr_round == 1 then --第一次开始，在匹配房标记一下
                R().fmatchsvr(1):send('.table_mgr','ftable_start',self_password)
            end
            --开始前删除记录
            check_del_record()
            curr_status = TABLE_STATUS_PLAYING
            notify_start(curr_zjh_instance)
            game_start_time = curr_time
        else --如果检查没法开始那么又回到等待状态
            curr_status = TABLE_STATUS_RESTART
            ready_timeout = curr_time
            notify_cancel_count_down()
        end
    elseif curr_status == TABLE_STATUS_PLAYING then
        if check_play(curr_time) then
            curr_status = TABLE_STATUS_GAMEOVER
            game_over_time = curr_time
        end
    elseif curr_status == TABLE_STATUS_GAMEOVER then
        local is_finish = true
        --如果是因为比牌结束游戏那么需要预留4S给客户端播放比牌动画
        if curr_zjh_instance:get_operate_delay_time() and curr_time - game_over_time < zjh.COMPARE_ANIMATION_TIME then
            is_finish = false
        end

        if is_finish then
            curr_zjh_instance:clear_operate_delay_time()
            local game_result = finish_game()
            if game_result then
                local ok,ret = xpcall(audit_game_result,debug.traceback,game_result)
                if not ok then
                    errlog(ret)
                end
            end
            --设置旧的庄家ID
            --old_banker_uid = curr_zjh_instance:get_banker_uid()
            curr_status = TABLE_STATUS_ANIMATION
            game_animation_time = curr_time
        end
    elseif curr_status == TABLE_STATUS_ANIMATION then
        if curr_time - game_animation_time > zjh.COINS_ANIMATION_TIME then
            kick_player_standup()
            check_stop_table() --停服
            curr_status = TABLE_STATUS_RESTART
        end
    elseif curr_status == TABLE_STATUS_RESTART then
        curr_zjh_instance = nil
        reset_all_player_ready() --默认将场上所有玩家自动设置为准备
        curr_status = TABLE_STATUS_WAITTING_READY
    else
        errlog('unknown status...',curr_status)
    end

    check_reconnect_timeout(curr_time)
    check_close_table(curr_time)
end

local function game_update()
    curr_status = TABLE_STATUS_WAITTING_READY
    while true do
        local curr_time = util.get_now_time()
        local ok,ret = xpcall(update,debug.traceback,curr_time)
        if not ok then
            errlog(ret)
        end
        skynet.sleep(50)
    end
end

function internal.get_player_num()
    return get_player_num()
end

---------------------------客户端请求类处理----------------------------------------
--[[
    请求看牌操作
]]
function handler.REQ_LOOK_CARD(uid,msg,game_session)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_LOOK_CARD curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_LOOK_CARD curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_LOOK_CARD game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_LOOK_CARD error player_info is nil", uid)
        return false
    end

    --玩家还没坐下无法点击查看
    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_LOOK_CARD error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_LOOK_CARD uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_LOOK_CARD error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    if not curr_zjh_instance:can_look(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.LOOK_CARD_FAIL})
        dbglog("REQ_LOOK_CARD error ok is false", ok)
        return false
    end

    --send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.RSP_SUCESS})

    local card_type, tile_list = curr_zjh_instance:look_card(uid)
    send_to_gateway(uid,game_session,'zhajinhua.RSP_LOOK_CARD',{result = error_code.RSP_SUCESS, card_type = card_type, tile_list = tile_list})
    notify_others('zhajinhua.NTF_LOOK_CARD',uid,{uid = uid,tile_list = {}})  --tile_list客户端测试时开放

    --刷新一下新的按钮
    send_self_operate_status(uid)
    player_timeout[uid] = nil --清空连续超时记录
    add_record(RECORD_TYPE_LOOK,uid)

    return true
end

--[[
    请求放弃牌
]]
function handler.REQ_GIVE_UP(uid,msg,game_session,auto)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.GAME_NOT_START})
        dbglog("REQ_GIVE_UP curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.GAME_NOT_START})
        dbglog("REQ_GIVE_UP curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_GIVE_UP game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_GIVE_UP error player_info is nil", uid)
        return false
    end

    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_GIVE_UP error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_GIVE_UP uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_GIVE_UP error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_GIVE_UP error player is have operate lock", uid)
        return false
    end

    --在延迟比牌期间不能弃牌
    if curr_zjh_instance:get_operate_delay_time() then
        dbglog("REQ_GIVE_UP error because player in operate delay time")
        return false
    end

    if not curr_zjh_instance:can_give_up(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.GIVE_UP_FAIL})
        dbglog("REQ_GIVE_UP curr_zjh_instance:give_up failed", uid)
        return false
    end

    send_to_gateway(uid,game_session,'zhajinhua.RSP_GIVE_UP',{result = error_code.RSP_SUCESS})

    notify_all('zhajinhua.NTF_GIVE_UP',{uid = uid})
    if not auto then
        player_timeout[uid] = nil ----清空连续超时记录
    end
    --添加记录
    add_record(RECORD_TYPE_GIVEUP,uid)
    --放弃牌局
    local is_trun_next = curr_zjh_instance:give_up(uid)

    if is_trun_next then
        curr_zjh_instance:turn_next_player()
        ntf_next_turn_info()
        send_next_player_operate_status()
    end

    return true
end

local function check_roll_back(uid)
    if curr_status ~= TABLE_STATUS_PLAYING then
        errlog(uid,'check_roll_back because curr_status ~= TABLE_STATUS_PLAYING')
        return true
    end

    if curr_zjh_instance:is_game_over() then
        errlog(uid,'check_roll_back because curr_zjh_instance:is_game_over()')
        return true
    end

    if not curr_zjh_instance:is_my_turn(uid) then
        errlog(uid,'check_roll_back because is not my trun')
        return true
    end
    
    return false
end

--[[
    请求下注
]]
function handler.REQ_ADD_SCORE(uid,msg,game_session)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.GAME_NOT_START})
        dbglog("REQ_ADD_SCORE curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.GAME_NOT_START})
        dbglog("REQ_ADD_SCORE curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_ADD_SCORE game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_ADD_SCORE error player_info is nil", uid)
        return false
    end

    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_ADD_SCORE error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_ADD_SCORE uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_ADD_SCORE error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    local bet_score = msg.bet_score
    -- if bet_score == 0 then
    --     bet_score = nil
    -- end

    local ok,cost_score = curr_zjh_instance:can_add_score(uid,bet_score)
    if not ok then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
        errlog("REQ_ADD_SCORE curr_zjh_instance:add_score(uid,multiple) error", uid)
        return false
    end

    local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
    if not ok then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
        errlog(uid,'REQ_ADD_SCORE add_score failed to get base_data',uid)
        return false
    end

    --非比牌情况下如果身上的钱不够跟注了那么无法进行跟注
    local is_bet = true
    if base_data.coins < cost_score then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.GOLD_IS_NOT_ENOUGH})
        errlog(uid, 'REQ_ADD_SCORE fail because base_data.coins < cost_score')
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    --这里开始锁住玩家的操作了
    curr_zjh_instance:set_operate_lock(uid,true)

     --扣钱
    local robot = is_robot(uid)
    local ret = reduce_coins(uid,cost_score,reason.BET_COIN,{is_robot=robot},get_extra_bill_info(uid))
    if not ret then
        curr_zjh_instance:set_operate_lock(uid,false)
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
        errlog(uid,'REQ_ADD_SCORE reduce_coins failed to',uid)
        return false
    end

    --检查是否要回滚金币
    if check_roll_back(uid) then
        add_coins(uid,cost_score,reason.BET_COIN_BACK,{is_robot=robot},get_extra_bill_info(uid))
        curr_zjh_instance:set_operate_lock(uid,false)
        send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.BET_FAIL})
        errlog(uid,'roll back player coin',uid)
        return false
    end

    --如果此时无法
    curr_zjh_instance:add_score(uid,cost_score,is_bet,msg.add_type)

    --覆盖一下玩家缓存中的金币 展示使用
    if player_info then
        player_info.coins = ret.curr_coins
    end

    send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.RSP_SUCESS})

    local rsp = {
        uid = uid,
        bet_score = cost_score,
        left_score = ret.curr_coins,
        total_score = curr_zjh_instance:get_table_total_score(),
        add_type = msg.add_type,
        cur_bet_score = curr_zjh_instance:get_player_bet_score(uid)
    }

    notify_all('zhajinhua.NTF_ADD_SCORE',rsp)

    utils.notify_money_changed(uid,{coins = ret.curr_coins},game_session)
    
    --添加牌局记录
    local record_type = RECORD_TYPE_ADD
    if msg.add_type == ADD_TYPE_GEN then
        record_type = RECORD_TYPE_FOLLOW
    end
    add_record(record_type,uid,nil,nil,cost_score)

    --如果当前是我出手才切换下一个出手
    curr_zjh_instance:turn_next_player()
    ntf_next_turn_info()

    --通知下一个玩家的按钮状态
    send_next_player_operate_status()
    player_timeout[uid] = nil --清空连续超时记录

    curr_zjh_instance:set_operate_lock(uid,false)

    return true
end

--[[
    请求比牌
]]
function handler.REQ_COMPARE_CARD(uid,msg,game_session,is_force_compare)
    if curr_status ~= TABLE_STATUS_PLAYING then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_COMPARE_CARD curr_status is not playing !! ",curr_status)
        return false
    end

    if not curr_zjh_instance then
        --send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.GAME_NOT_START})
        dbglog("REQ_COMPARE_CARD curr_zjh_instance is nil !! ")
        return false
    end

    if curr_zjh_instance:is_game_over() then
        dbglog("REQ_COMPARE_CARD game is over !! ")
        return false
    end

    --桌子里面没有该玩家了
    local player_info = player_info_list[uid]
    if not player_info then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NO_PLAYER_IN_TABLE})
        dbglog("REQ_COMPARE_CARD error player_info is nil", uid)
        return false
    end

    if not player_info.position then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_COMPARE_CARD error player_info.position is nil", uid)
        return false
    end

    --玩家位置出错了
    if uid ~= ordered_players[player_info.position] then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NO_PLAYER_IN_POSITION})
        dbglog("REQ_COMPARE_CARD uid ~= ordered_players[player_info.position]", uid)
        return false
    end

    --检查一下状态
    local player_status = player_status_list[uid]
    if not player_status or player_status ~= PLAYER_STATUS_PLAYING then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.NOT_IN_PLAYERING})
        dbglog("REQ_COMPARE_CARD error player_status is nil or player_status ~= PLAYER_STATUS_PLAYING", uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    --检查是否可以下注
    local ok,cost_score = curr_zjh_instance:can_add_score(uid)
    if not ok then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.COMPARE_FAIL})
        errlog("REQ_COMPARE_CARD curr_zjh_instance:add_score(uid,multiple) error", uid)
        return false
    end

    local ok,base_data = R().basesvr({key=uid}):call('.msg_handler','get_base_data',uid)
    if not ok then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.COMPARE_FAIL})
        errlog(uid,'REQ_COMPARE_CARD add_score failed to get base_data',uid)
        return false
    end

    local enough_money = true
    local is_force = false
    local dst_uid = msg.dst_uid
    if base_data.coins < cost_score then
        enough_money = false
        cost_score = base_data.coins
        --钱不够强制跟下一家比
        dst_uid = curr_zjh_instance:get_next_compare_player_uid()
        is_force = true
    end

    --检查一下是否可以比牌
    if not curr_zjh_instance:can_compare(uid,dst_uid,is_force) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.COMPARE_FAIL})
        errlog("REQ_COMPARE_CARD not curr_zjh_instance:can_compare", uid, dst_uid)
        return false
    end

    --检查玩家是否有操作锁住了
    if curr_zjh_instance:get_operate_lock(uid) then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_COMPARE_CARD',{result = error_code.ERROR_IN_OPERATE_LOCK})
        dbglog("REQ_ADD_SCORE error player is have operate lock", uid)
        return false
    end

    --这里开始锁住玩家的操作了
    curr_zjh_instance:set_operate_lock(uid,true)

    if cost_score > 0 then
        --扣钱
        local robot = is_robot(uid)
        local ret = reduce_coins(uid,cost_score,reason.BET_COIN,{is_robot=robot},get_extra_bill_info(uid))
        if not ret then
            curr_zjh_instance:set_operate_lock(uid,false)
            return false
        end

        --检查是否要回滚金币
        if check_roll_back(uid) then
            add_coins(uid,cost_score,reason.BET_COIN_BACK,{is_robot=robot},get_extra_bill_info(uid))
            curr_zjh_instance:set_operate_lock(uid,false)
            return false
        end

        curr_zjh_instance:add_score(uid,cost_score,enough_money,2)

        --覆盖一下玩家缓存中的金币 展示使用
        if player_info then
            player_info.coins = ret.curr_coins
        end
    end

    --开始比牌逻辑
    local win,is_trun_next,src_type,dst_type = curr_zjh_instance:compare(uid,dst_uid)
    local win_uid = 0
    local fail_uid = 0
    if win then
        win_uid = uid
        fail_uid = dst_uid
    else
        win_uid = dst_uid
        fail_uid = uid
    end

    send_to_gateway(uid,game_session,'zhajinhua.RSP_ADD_SCORE',{result = error_code.RSP_SUCESS})

    local rsp = {
        src_uid = uid,
        dst_uid = dst_uid,
        win_uid = win_uid,
        fail_uid = fail_uid,
        bet_score = cost_score,
        left_score = player_info.coins,
        total_score = curr_zjh_instance:get_table_total_score(),
        cur_bet_score = curr_zjh_instance:get_player_bet_score(uid),
        src_type = src_type,
        dst_type = dst_type,
    }
    notify_all('zhajinhua.NTF_COMPARE_CARD', rsp)
    --添加比牌记录
    add_record(RECORD_TYPE_COMPARE,uid,dst_uid,win_uid)

    utils.notify_money_changed(uid,{coins = player_info.coins},game_session)

    curr_zjh_instance:set_operate_delay_time()
    if is_trun_next then
        if not win then
            curr_zjh_instance:turn_next_player()
        else
            curr_zjh_instance:reset_play_end_time()
        end
    end
    curr_zjh_instance:set_operate_lock(uid,false)

    return true
end

--[[
    请求聊天
]]
function handler.REQ_CHAT(uid,msg)
    print("=======================ggggggggggggggg",uid,tostring_r(msg))
    local player_info = assert(player_info_list[uid])
    if not player_info then
        errlog(uid,"REQ_CHAT failed you are not a player_info")
        return false
    end

    if not player_info.position then
        errlog(uid,"REQ_CHAT not have position")
        return false
    end

    local curr_time = util.get_now_time()

    if player_info.last_chat_time and curr_time - player_info.last_chat_time < 1 then
        send_to_gateway(uid,table_players[uid],'table.RSP_CHAT',{result = error_code.REQ_CHAT_TOO_FAST})
        return false
    end

    player_info.last_chat_time = curr_time

    send_to_gateway(uid,table_players[uid],'table.RSP_CHAT',{result = error_code.RSP_SUCESS})

    local ntf = {
        uid = uid,
        type = msg.type,
        picture_id = msg.picture_id,
        content = msg.content,
        voice = msg.voice,
        content_id = msg.content_id
    }

    notify_all('table.NTF_CHAT',ntf)

    return true
end

--用户请求坐下
function handler.REQ_PLAYER_SEAT(uid,msg)
    local position = msg.position
    local status = msg.status
    --判断坐下位置是否有效
    if position < 1 or position > zjh.MAX_PLAYER_NUM then
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.ERROR_HAVE_STAND_UP})
        return false
    end

    if status then
        --判断玩家是否有该玩家
        local player_info = player_info_list[uid]
        if not player_info then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.NO_PLAYER_IN_TABLE})
            return false
        end

        --判断该玩家是否已经坐下了
        if player_info.position then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.SEAT_FAIL_HAVE_SEAT})
            return false
        end

        --判断该位置是否已经被占用了
        if ordered_players[position] then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.SEAT_IS_EMPLOY})
            return false
        end

        local roomdata = self_game_config
        if not roomdata then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.SEAT_FAIL})
            errlog('REQ_PLAYER_SEAT fail because roomdata is nil')
            return false
        end

        --这里在检查一把是否要将玩家和机器人进行站起或者离开
        if player_info.coins < roomdata.min then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.GOLD_IS_NOT_ENOUGH})
            return false
        end

        if roomdata.max ~= 0 and player_info.coins > roomdata.max then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.TO_MUCH_COIN})
            return false
        end

        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.RSP_SUCESS})
        --坐下
        sit_down(uid,position)
    else
        local player_info = player_info_list[uid]
        if not player_info then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.NO_PLAYER_IN_TABLE})
            return false
        end

        if not player_info.position then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.UP_FAIL_NOT_HAVE_SEAT})
            return false
        end

        if uid ~= ordered_players[player_info.position] then
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.UP_FAIL_NOT_HAVE_SEAT})
            return false
        end

        --判断玩家之前有没有其他还未解锁的操作
        if curr_zjh_instance then
            --锁住操作了就不让玩家站起
            if curr_zjh_instance:get_operate_lock(uid) then
                send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.ERROR_IN_OPERATE_LOCK})
                errlog("stand_up error player is have operate lock", uid)
                return false
            end

            --在延迟比牌期间不能站起
            if curr_zjh_instance:get_operate_delay_time() then
                dbglog("REQ_PLAYER_SEAT error because player in operate delay time")
                return false
            end
        end

        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_PLAYER_SEAT',{result = error_code.RSP_SUCESS})
        --站起
        stand_up(uid)
    end

    return true
end

--换桌
function handler.REQ_TABLE_CHANGE(uid,msg,game_session)
    send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_TABLE_CHANGE',{result = error_code.PERMISSION_DENIDE})
    return false
end

--[[
    玩家请求离开房间
]]
function handler.REQ_LEAVE(uid,msg,game_session)
    if table_players[uid] ~= game_session then
        errlog(uid,'invalid status',table_players[uid],game_session)
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_LEAVE',{result = error_code.PERMISSION_DENIDE})
        return false
    end

    local player_info = player_info_list[uid]
    if not player_info then
        dbglog(uid,'handler.REQ_LEAVE player_info is nil')
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_LEAVE',{result = error_code.PERMISSION_DENIDE})
        return false
    end

    local pos = player_info.position

    --检查是否可以离开操作
    if curr_zjh_instance then
        --锁住操作了就不让玩家站起
        if curr_zjh_instance:get_operate_lock(uid) then
            dbglog("handler.REQ_LEAVE error player is have operate lock", uid)
            send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_LEAVE',{result = error_code.ERROR_IN_OPERATE_LOCK})
            return false
        end

        --离开期间不能弃牌
        if curr_zjh_instance:get_operate_delay_time() then
            dbglog("REQ_LEAVE error because player in operate delay time")
            return false
        end
    end

    leave(uid)

    if not is_robot(uid) then
        local init_coins = player_info.init_coins or 0
        R().hallsvr({key=uid}):send('.msg_handler', 'check_lucky_tigger',uid,self_game_type,init_coins)
    end
    send_to_gateway(uid,game_session,'zhajinhua.RSP_LEAVE',{result = error_code.RSP_SUCESS})

    -- watch_session(game_session,uid,false)

    -- skynet.send('.table_mgr','lua','leave',uid)

    return true
end

function handler.REQ_USE_MAGIC_PICTURE(uid,msg,game_session)
    local src_player_info = player_info_list[uid]
    if not src_player_info then
        errlog(uid,"REQ_USE_MAGIC_PICTURE failed you are not a src_player_info")
        return false
    end

    if not src_player_info.position then
        send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{result = error_code.USE_ITEM_NEED_POSTION})
        return false
    end

    local dst_player_info = player_info_list[msg.dst_id]
    if not dst_player_info then
        errlog(msg.dst_id,"REQ_USE_MAGIC_PICTURE failed you are not a dst_player_info")
        return false
    end

    if not dst_player_info.position then
        errlog(uid,"REQ_USE_MAGIC_PICTURE not have position")
        return false
    end

    -- local ret = reduce_coins(uid,constant.USE_MAGIC_PICTURE_COIN,reason.USE_MAGIC_PICTRUE,get_extra_bill_info(uid))
    -- if not ret then
    --     send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{result = error_code.GOLD_IS_NOT_ENOUGH})
    --     return false
    -- end

    -- src_player_info.coins = ret.curr_coins
    send_to_gateway(uid,table_players[uid],'table.RSP_USE_MAGIC_PICTURE',{result = error_code.RSP_SUCESS})

    notify_all('table.NTF_USE_MAGIC_PICTURE',{src_id = uid, dst_id = msg.dst_id, picture_id = msg.picture_id})
    return true
end

function handler.REQ_AUTO_BET(uid,msg,game_session)
    local player_info = player_info_list[uid]
    if not player_info then
        errlog(uid,"REQ_USE_MAGIC_PICTURE failed you are not a player_info")
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_AUTO_BET',{result = error_code.PLAYER_HAS_NO_TABLE})
        return false
    end

    if not player_info.position then
        errlog(uid,"REQ_USE_MAGIC_PICTURE not have position")
        send_to_gateway(uid,table_players[uid],'zhajinhua.RSP_AUTO_BET',{result = error_code.PLAYER_HAS_NO_TABLE})
        return false
    end

    if not curr_zjh_instance then
        send_to_gateway(uid,game_session,'zhajinhua.RSP_AUTO_BET',{result = error_code.GAME_NOT_START})
        return false
    end

    curr_zjh_instance:set_auto_bet(uid,msg.is_auto)

    send_to_gateway(uid,game_session,'zhajinhua.RSP_AUTO_BET',{is_auto = msg.is_auto})

    send_self_operate_status(uid)

    return true
end

local function update_player_coins(uid, coins)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = coins
    else
        errlog(string_format("uid(%d) coins(%d) player info not exist", uid, coins))
    end
end

local function check_have_enough_coins(uid,coins)
    local player_info = player_info_list[uid]
    if not player_info or player_info.coins < coins then
        return false
    end
    return true
end

function handler.REQ_OPEN_CAISHEN(uid,msg)
    send_to_gateway(uid,table_players[uid],'table.RSP_OPEN_CAISHEN',{result = error_code.INPUT_ERROR})
    return false
end

local function copy_table(t)
    local ret = {}
    for k,v in pairs(t) do
        ret[k] = v
    end
    return ret
end

function handler.REQ_RECORD_LIST(uid,msg,game_session)
    print("=============REQ_RECORD_LIST",game_session,tostring_r(op_record_list))
    local rsp_record_list = {}
    for round,op_list in pairs(op_record_list) do
        local record_info = {}
        if round == curr_round then
            record_info.round_type = ROUND_TYPE_CURR
        else
            record_info.round_type = ROUND_TYPE_LAST
        end
        record_info.op_list = copy_table(op_list)
        table_insert(rsp_record_list,record_info)
    end
    table_sort(rsp_record_list,function(a,b) return a.round_type < b.round_type end)
    print_r(rsp_record_list)
    send_to_gateway(uid,game_session,'zhajinhua.RSP_RECORD_LIST',{record_list = rsp_record_list})

    return true
end

-- 掉线回调接口
function internal.disconnect(uid,game_session)
    dbglog(uid,'disconnect...',table_players[uid],game_session)
    if table_players[uid] ~= game_session then
        errlog(uid,'invalid status',table_players[uid],game_session)
        return
    end

    local ret = leave(uid,0)
    dbglog(uid,'disconnect...',ret)
    return true
end

function internal.stop_server()
    stopping_server = true
end

-- 关服回调接口
function internal.close_server()
    closing_server = true
end

-- 客户端其请求进入房间
function internal.enter(uid,game_session,msg)
    local ok,r = enter(uid,game_session,msg)
    if not ok then
        send_to_gateway(uid,game_session,'table.RSP_ENTER',{result = r})
        return false
    end
  
    r.result = error_code.RSP_SUCESS
    send_to_gateway(uid,game_session,'table.RSP_ENTER',r)

    notify_player_enter(uid)
    --跟网关agent绑定seesion监控 网关有关闭事件进行通知
    watch_session(game_session,uid,true)
    
    return true
end

-- 延长关房间时间
function internal.touch(key)
    if recycling_table_start_time then
        recycling_table_start_time = recycling_table_start_time + 10
    end

    return self_table_type
end

-- 服务开启设置房间参数
function internal.start(conf)
    tablesvr_id = tonumber(skynet.getenv "server_id")

    self_table_id   = conf.table_id
    self_table_type = conf.table_type
    this_table_gid  = conf.table_gid
    self_game_type  = conf.game_type

    curr_round    = 0
    table_info    = conf.payload
    self_password = table_info.password
    self_club_id  = table_info.club_id

    self_game_config = global_configs.clubroomdata[table_info.conf_id]

    print("zjhftable_start===============",table_info.conf_id,self_password,self_game_type,self_table_type,self_club_id)
    skynet.fork(game_update)

    return true
end

function internal.exit()
    skynet.exit()
end

--通知桌子金钱发现改变
function internal.update_coins_on_table(uid,coins,safe_box)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.coins = coins
        if curr_zjh_instance then
            local next_player_id = curr_zjh_instance:get_next_player_uid()
            if next_player_id == uid then
                --金钱发生改变要通知玩家的按钮状态也发现变化
                local buttons_status = curr_zjh_instance:get_buttons_status(uid,player_info.coins,is_robot(uid))
                send_to_gateway(uid,table_players[uid],'zhajinhua.NTF_PLAYER_OPERATE_STATUS',{buttons_status = buttons_status})

            end
        end
        if safe_box then
            player_info.safe_box = safe_box
        end
        local chged_list = {}
        table_insert(chged_list,{uid=uid,coins=coins})
        --print(tostring_r(chged_list))
        notify_all('table.NTF_MONEY_CHANGED',{chged_list=chged_list})
    end
end

function internal.get_ftable_info()
    local table_data = {}

    table_data.password = self_password
    table_data.table_type = self_table_type
    table_data.cur_player_num = get_player_num()
    table_data.max_player_num = zjh.MAX_PLAYER_NUM
    table_data.dizhu = self_game_config.dizhu

    return table_data
end

function internal.get_game_type()
    return self_game_type,self_table_type
end

local function get_non_robot_players_num()
    local player_num = 0

    for _,uid in pairs(ordered_players) do
        if not is_robot(uid) then
            player_num = player_num + 1
        end        
    end

    return player_num    
end

function internal.get_user_playing_info()
    local playing_info = {}
    playing_info.game_type = self_game_type
    playing_info.table_type = self_table_type
    playing_info.total = get_non_robot_players_num()

    return playing_info
end

--=================================table protocols=================
local function update_player_heartbeat(uid)
    local player_info = player_info_list[uid]
    if player_info then
        player_info.last_ping_time = util.get_now_time()
    end
end

local function get_msg_module_name(msgid)
    local m = msgdef.id_to_name[msgid]
    if not m then return end
    return m[1],m[2] --[1]->module,[2]->name
end

function dispatch_client_message(game_session,uid,msg,size)
    local _,msgid,pbmsg,pbsize = proxypack.unpack_client_message(msg,size)
    local module,name = get_msg_module_name(msgid)

    if not module or not name then
        print('invalid msgid',msgid,module,name)
        return
    end

    local pbname = module .. '.' .. name
    local req_msg = pb.decode(pbname,pbmsg,pbsize)

    if not req_msg then
        errlog('------------unknown request-----------',pbname)
        return
    end

    dbglog(string.format('[%s]>>>>>player[%s] got a request[%s] content(%s)',
        skynet.address(skynet.self()),tostring(uid),pbname,tostring_r(req_msg)))

    local f = handler[name]
    if not f then
        errlog('unknown action',pbname)
        return
    end

    local ret = f(uid,req_msg,game_session)
    if not ret then
        errlog(string.format('failed to handle requrest(%s.%s)',module,name))
    end

    update_player_heartbeat(uid)
end

local function dispatch(_,_,game_session,uid,data)
    local msg,size = proxypack.pack_raw(data)
    local ok,errmsg = xpcall(dispatch_client_message,debug.traceback,game_session,uid,msg,size)
    skynet.trash(msg,size)  --这里需要保证内存被释放
    if not ok then 
        errlog(errmsg)
    end
end


function handle_lua_req(session,source,action,...)
    dbglog('internal request',action,...)
    local f = internal[action]
    if f then
        skynet.retpack(f(...))
    else
        handler[action](...)
    end
end

function start()
    skynet.register_protocol {
        name = "client",
        id = skynet.PTYPE_CLIENT,
        unpack = skynet.unpack,
        dispatch = dispatch
    }

    skynet.start(function()
        skynet.dispatch("lua",function(session,source,action,...)
            handle_lua_req(session,source,action,...)
        end)

        sharedata.query("global_configs")
        global_configs = setmetatable({},{
            __index = function(t,k) 
                return sharedata.query("global_configs")[k]
            end
        })
        _G.global_configs = global_configs
    end)
end

return _ENV
